﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HtmlAgilityPack;

namespace Kooboo.HtmlFunc.Analysis
{
    public class VisitorDispenser
    {
        private List<VisitorBase> AcceptedVisitors;

        public VisitorDispenser(VisitorContext context)
        {
            this.Context = context;
            this.AcceptedVisitors = new List<VisitorBase>();
        }

        public VisitorContext Context
        {
            get;
            private set;
        }

        public void Accept(VisitorBase visitor)
        {
            this.AcceptedVisitors.Add(visitor);
        }

        public void Accept(IEnumerable<VisitorBase> visitors)
        {
            this.AcceptedVisitors.AddRange(visitors);
        }

        public bool Detach(VisitorBase visitor)
        {
            return this.AcceptedVisitors.Remove(visitor);
        }

        public void Visit(HtmlDocument document)
        {
            this.VisitDocument(document);
            this.Visit(document.DocumentNode);
        }

        public void Visit(HtmlNode node)
        {
            if (node == null)
            {
                return;
            }

            var comment = node as HtmlCommentNode;
            if (comment != null)
            {
                this.VisitCommentNode(comment);
            }

            var textNode = node as HtmlTextNode;
            if (textNode != null)
            {
                this.VisitTextNode(textNode);
            }

            if (comment == null &&
                textNode == null)
            {
                this.VisitNode(node);
            }

            if (node.Attributes != null)
            {
                for (var i = 0; i < node.Attributes.Count; i++)
                {
                    this.VisitAttribute(node.Attributes[i]);
                }
            }

            if (node.ChildNodes != null)
            {
                for (var i = 0; i < node.ChildNodes.Count; i++)
                {
                    this.Visit(node.ChildNodes[i]);
                }
            }
        }

        public void VisitAll(object obj)
        {
            this.AcceptedVisitors.ForEach((visitor) => { visitor.VisitAll(obj); });
        }

        public void VisitDocument(HtmlDocument document)
        {
            this.VisitAll(document);
            this.AcceptedVisitors.ForEach((visitor) => { visitor.VisitDocument(document); });
        }

        public void VisitNode(HtmlNode node)
        {
            this.VisitAll(node);
            this.AcceptedVisitors.ForEach((visitor) => { visitor.VisitNode(node); });
        }

        public void VisitAttribute(HtmlAttribute attribute)
        {
            this.VisitAll(attribute);
            this.AcceptedVisitors.ForEach((visitor) => { visitor.VisitAttribute(attribute); });
        }

        public void VisitCommentNode(HtmlCommentNode commentNode)
        {
            this.VisitAll(commentNode);
            this.AcceptedVisitors.ForEach((visitor) => { visitor.VisitCommentNode(commentNode); });
        }

        public void VisitTextNode(HtmlTextNode textNode)
        {
            this.VisitAll(textNode);
            this.AcceptedVisitors.ForEach((visitor) => { visitor.VisitTextNode(textNode); });
        }
    }
}
